﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using Formboard.Resources;
using System.Xml.Serialization;
using System.Xml;
using Formboard.Request;

namespace Formboard
{
    public class HttpRequestProvider
    {
        #region members
        private HttpWebRequest request;
        private HttpWebResponse answer;
        private String uriBase;
        public String port;
        
        #endregion

        #region test

        public void sendRequest()
        {
           // System.console.ReadKey();
        }

        public void Lirerequest()
        {
           /* this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf+":8080");
            this.request.Method = "GET";

            this.answer = (HttpWebResponse)this.request.GetResponse();
            //System.//console.WriteLine(this.answer.Conten);
            StreamReader Sr = new StreamReader(((HttpWebResponse)this.request.GetResponse()).GetResponseStream());
            response = Sr.ReadToEnd(); // On choppe la réponse
            Sr.Close(); // Et on ferme
            System.//console.WriteLine(response);
            System.//console.ReadKey();*/
        }
        #endregion
        #region Cstor
        public HttpRequestProvider(String Uri,String port)
        {
            Params.Parameters.urlConf = Uri;
            this.uriBase = Uri;
            this.port = port;
        }
        #endregion
        
        #region Methods

       
        public void getConfiguration()
        {
            this.request = (HttpWebRequest)WebRequest.Create(this.uriBase + ":" + this.port);
            this.request.Method = "GET";           
            this.answer = (HttpWebResponse)this.request.GetResponse();

            XmlSerializer desarializer = new XmlSerializer(typeof(GetConfigurationRequest), new XmlRootAttribute("goimerir"));
            GetConfigurationRequest newConfig = (GetConfigurationRequest)desarializer.Deserialize(this.answer.GetResponseStream());
            Params.Parameters.urlConf = newConfig.urls.Last().href;
           
        }
        
        private String SerializeRequest(Object req)
        {         
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            String XmlizedString = null;
            MemoryStream memoryStream = new MemoryStream();
            XmlSerializer xs = new XmlSerializer(req.GetType(), new XmlRootAttribute("goimerir"));
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);

            xs.Serialize(xmlTextWriter, req,ns);
            memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
            XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());

            //console.WriteLine(XmlizedString);
            //console.ReadKey(true);
            return XmlizedString;

        }

        private static String UTF8ByteArrayToString(Byte[] characters)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            String constructedString = encoding.GetString(characters);
            return (constructedString);
        }

        
        private static Byte[] StringToUTF8ByteArray(String pXmlString)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            Byte[] byteArray = encoding.GetBytes(pXmlString);
            return byteArray;
        }

        /// <summary>
        /// This function notify the server that a new user was created
        /// </summary>
        /// <param name="newuser">the user who want to be create</param>
        public void createUser(User newUser)
        {
            byte [] postData;            
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf+":"+this.port+"/users/");            
            this.request.Method = "POST";
            this.request.ContentType = "text/xml";
            postData = Encoding.UTF8.GetBytes(SerializeRequest(new AddUserRequest(newUser)));                        
            this.request.ContentLength = postData.Length;                             
            Stream requestStream = this.request.GetRequestStream();            
            requestStream.Write(postData, 0, postData.Length);
            requestStream.Close();
            answer =((HttpWebResponse)request.GetResponse());
            int iStatCode = (int)answer.StatusCode;
            string sStatus = iStatCode.ToString();
           // //console.WriteLine("Status Code: {0}", sStatus);

        }

        public void createBoard(Board newBoard)
        {
            byte[] postData;
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/");
            this.request.Method = "POST";
            this.request.ContentType = "text/xml";
            this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
            postData = Encoding.UTF8.GetBytes(SerializeRequest(new CreateANewBoardRequest(newBoard)));
            this.request.ContentLength = postData.Length;          
            Stream requestStream = this.request.GetRequestStream();
            requestStream.Write(postData, 0, postData.Length);
            requestStream.Close();
            answer = ((HttpWebResponse)request.GetResponse());
            int iStatCode = (int)answer.StatusCode;
            string sStatus = iStatCode.ToString();
           // //console.WriteLine("Status Code: {0}", sStatus);
        }

        public List<User> getUsers()
        {
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":"+this.port+"/users/");
            this.request.Method = "GET";
            this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
            this.answer = (HttpWebResponse)this.request.GetResponse();

            XmlSerializer desarializer = new XmlSerializer(typeof(GetUserListRequest), new XmlRootAttribute("goimerir"));
            GetUserListRequest userList = (GetUserListRequest)desarializer.Deserialize(this.answer.GetResponseStream());

            List<User> toreturn = new List<User>();

           foreach (Formboard.Request.GetUserListRequest.User unUser in userList.users)
            {
               User obj= new User();
               obj.fullname=unUser.fullname;
               obj.screenname=unUser.name;
               obj.url=unUser.url;
               toreturn.Add(obj);
            }
                      
            
            return toreturn;
        }

        public List<Board> getBoards()
        {
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/");

            this.request.Method = "GET";
            this.request.Headers.Add("Authorization","Basic "+Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name+":"+Params.Parameters.password)));
            this.answer = (HttpWebResponse)this.request.GetResponse();
            XmlSerializer desarializer = new XmlSerializer(typeof(GetBoardListRequest), new XmlRootAttribute("goimerir"));
            GetBoardListRequest boardList = (GetBoardListRequest)desarializer.Deserialize(this.answer.GetResponseStream());

            List<Board> toreturn = new List<Board>();

            foreach (Formboard.Request.GetBoardListRequest.Board oneBoard in boardList.boards)
            {
                Board obj = new Board();
                obj.creation_date = oneBoard.creation_date;
                obj.name= oneBoard.name;
                obj.owner= oneBoard.owner;
                obj.invitee = oneBoard.invitee;
                obj.status =(Board.BoardStatus) Enum.Parse(typeof(Board.BoardStatus), oneBoard.status);
                obj.url = oneBoard.url;
                toreturn.Add(obj);
            }
            return toreturn;
        }

        public void createInvite(String inviteName, Board boardToJoin)
        {
            byte[] postData;
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/users/"+inviteName+"/invite/");
            this.request.Method = "POST";
            this.request.ContentType = "text/xml";
            this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
            postData = Encoding.UTF8.GetBytes(SerializeRequest(new InviteUserBoardRequest(boardToJoin)));
            this.request.ContentLength = postData.Length;
            Stream requestStream = this.request.GetRequestStream();
            requestStream.Write(postData, 0, postData.Length);
            requestStream.Close();
            answer = ((HttpWebResponse)request.GetResponse());
            int iStatCode = (int)answer.StatusCode;
            string sStatus = iStatCode.ToString();
          //  //console.WriteLine("Status Code: {0}", sStatus);
        }

        public void askPermissionToJoin(User userWantToJoin,Board boardToJoin)
        {
            byte[] postData;
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port +"/boards/"+boardToJoin.name+"/requests/");            
            this.request.Method = "POST";
            this.request.ContentType = "text/xml";
            this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
            postData = Encoding.UTF8.GetBytes(SerializeRequest(new PermissionJoinBoardRequest(userWantToJoin)));
            this.request.ContentLength = postData.Length;
            Stream requestStream = this.request.GetRequestStream();
            requestStream.Write(postData, 0, postData.Length);
            requestStream.Close();
            answer = ((HttpWebResponse)request.GetResponse());
            int iStatCode = (int)answer.StatusCode;
            string sStatus = iStatCode.ToString();
         //   //console.WriteLine("Status Code: {0}", sStatus);
        }

        public void removeABoard(Board boardToRemove)
        {
           
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/" + boardToRemove.getIdFromUrl());            
            this.request.Method = "DELETE";
            this.request.ContentType = "text/xml";                        
            Stream requestStream = this.request.GetRequestStream();            
            requestStream.Close();
            answer = ((HttpWebResponse)request.GetResponse());
            int iStatCode = (int)answer.StatusCode;
            string sStatus = iStatCode.ToString();
            //console.WriteLine("Status Code: {0}", sStatus);
        }

        public void loadAllTheBoard(Board boardToLoad)
        {
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/"+boardToLoad.name);
            this.request.Method = "GET";
            this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
            this.answer = (HttpWebResponse)this.request.GetResponse();
            XmlSerializer desarializer = new XmlSerializer(typeof(RetrieveABoardToPlayRequest), new XmlRootAttribute("goimerir"));
            RetrieveABoardToPlayRequest boardData = (RetrieveABoardToPlayRequest)desarializer.Deserialize(this.answer.GetResponseStream());

            boardToLoad.owner_white = boardData.board.owner_white.value;
            /*Filling moves's list*/
            foreach (RetrieveABoardToPlayRequest.Move aMove in boardData.board.moves)
            {
                Move oneMove = new Move();
                oneMove.Sequence = aMove.seq;
                oneMove.Row= aMove.row;
                oneMove.Column= aMove.column;
                boardToLoad.moves.Add(oneMove);
            }

        }

        public void playAMoveRequest(Move aMove , Board board)
        {
            lock (this)
            {
                byte[] postData;
                //  this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/"+board.getIdFromUrl()+"/moves/");
                this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/" + board.name + "/moves/");
                this.request.Method = "POST";
                this.request.ContentType = "text/xml";
                this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
                postData = Encoding.UTF8.GetBytes(SerializeRequest(new PlayAMoveRequest(aMove)));
                this.request.ContentLength = postData.Length;
                Stream requestStream = this.request.GetRequestStream();
                requestStream.Write(postData, 0, postData.Length);
                requestStream.Close();
                answer = ((HttpWebResponse)request.GetResponse());
                int iStatCode = (int)answer.StatusCode;
                string sStatus = iStatCode.ToString();
                //console.WriteLine("Status Code: {0}", sStatus);
            }
        }
        public List<Move> getBoardHistory(Board b, int start,int end)
        {
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/" + b.getIdFromUrl()+"&start="+start+"&end="+end);
            this.request.Method = "GET";
            this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
            this.answer = (HttpWebResponse)this.request.GetResponse();
            XmlSerializer desarializer = new XmlSerializer(typeof(GetMoveHistoryRequest), new XmlRootAttribute("goimerir"));
            GetMoveHistoryRequest history = (GetMoveHistoryRequest)desarializer.Deserialize(this.answer.GetResponseStream());
            List<Move> toReturn = new List<Move>();
            foreach (GetMoveHistoryRequest.Move aMove in history.moves.moves)
            {
                Move newMove = new Move();
                newMove.Sequence = aMove.seq;
                newMove.Row = aMove.row;
                newMove.Column = aMove.column;

            }
            return toReturn;
        }
        public List<Move> getBoardStartHistory(Board b, int end)
        {
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/" + b.getIdFromUrl() + "&end=" + end);
            this.request.Method = "GET";
            this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
            this.answer = (HttpWebResponse)this.request.GetResponse();
            XmlSerializer desarializer = new XmlSerializer(typeof(GetMoveHistoryRequest), new XmlRootAttribute("goimerir"));
            GetMoveHistoryRequest history = (GetMoveHistoryRequest)desarializer.Deserialize(this.answer.GetResponseStream());
            List<Move> toReturn = new List<Move>();
            foreach (GetMoveHistoryRequest.Move aMove in history.moves.moves)
            {
                Move newMove = new Move();
                newMove.Sequence = aMove.seq;
                newMove.Row = aMove.row;
                newMove.Column = aMove.column;

            }
            return toReturn;
        }
        public List<Move> getBoardEndHistory(Board b, int start)
        {
            this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/" + b.getIdFromUrl()+ "&start=" + start);
            this.request.Method = "GET";
            this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
            this.answer = (HttpWebResponse)this.request.GetResponse();
            XmlSerializer desarializer = new XmlSerializer(typeof(GetMoveHistoryRequest), new XmlRootAttribute("goimerir"));
            GetMoveHistoryRequest history = (GetMoveHistoryRequest)desarializer.Deserialize(this.answer.GetResponseStream());
            List<Move> toReturn = new List<Move>();
            foreach (GetMoveHistoryRequest.Move aMove in history.moves.moves)
            {
                Move newMove = new Move();
                newMove.Sequence = aMove.seq;
                newMove.Row = aMove.row;
                newMove.Column = aMove.column;

            }
            return toReturn;
        }
        public Move getLastSequence(Board b)
        {
            lock (this)
            {
                this.request = (HttpWebRequest)WebRequest.Create(Params.Parameters.urlConf + ":" + this.port + "/boards/" + b.name + "/moves/?last=1");
                this.request.Method = "GET";
                this.request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(Params.Parameters.name + ":" + Params.Parameters.password)));
                this.answer = (HttpWebResponse)this.request.GetResponse();
                XmlSerializer desarializer = new XmlSerializer(typeof(GetMoveHistoryRequest), new XmlRootAttribute("goimerir"));
                GetMoveHistoryRequest history = (GetMoveHistoryRequest)desarializer.Deserialize(this.answer.GetResponseStream());

                if (history.moves.moves.Count() == 0)
                {
                    return null;
                }
                else
                {
                    Move toReturn = new Move();
                    toReturn.Sequence = history.moves.moves.Last().seq;
                    toReturn.Row = history.moves.moves.Last().row;
                    toReturn.Column = history.moves.moves.Last().column;
                    return toReturn;
                }
            }
        }
        #endregion
    }
}
